1 : <?php
2 : /**
3 : * Container implementation.
4 : *
5 : * PHP Version 5
6 : *
7 : * @category Ding
8 : * @package Container
9 : * @subpackage Impl
10 : * @author Marcelo Gornstein <marcelog@gmail.com>
11 : * @license http://marcelog.github.com/ Apache License 2.0
12 : * @link http://marcelog.github.com/
13 : *
14 : * Copyright 2011 Marcelo Gornstein <marcelog@gmail.com>
15 : *
16 : * Licensed under the Apache License, Version 2.0 (the "License");
17 : * you may not use this file except in compliance with the License.
18 : * You may obtain a copy of the License at
19 : *
20 : * http://www.apache.org/licenses/LICENSE-2.0
21 : *
22 : * Unless required by applicable law or agreed to in writing, software
23 : * distributed under the License is distributed on an "AS IS" BASIS,
24 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
25 : * See the License for the specific language governing permissions and
26 : * limitations under the License.
27 : *
28 : */
29 : namespace Ding\Container\Impl;
30 :
31 : use Ding\Helpers\ErrorHandler\ErrorInfo;
32 :
33 : use Ding\Bean\IBeanDefinitionProvider;
34 : use Ding\Cache\Impl\DummyCacheImpl;
35 : use Ding\Bean\Provider\Core;
36 : use Ding\Resource\Impl\IncludePathResource;
37 : use Ding\Resource\Impl\FilesystemResource;
38 : use Ding\Resource\Impl\URLResource;
39 : use Ding\Cache\Locator\CacheLocator;
40 : use Ding\Container\IContainer;
41 : use Ding\Aspect\AspectManager;
42 : use Ding\Aspect\InterceptorDefinition;
43 : use Ding\Aspect\AspectDefinition;
44 : use Ding\Aspect\Interceptor\IDispatcher;
45 : use Ding\Aspect\Interceptor\DispatcherImpl;
46 : use Ding\Reflection\ReflectionFactory;
47 : use Ding\Bean\Lifecycle\BeanLifecycle;
48 : use Ding\Bean\Lifecycle\BeanLifecycleManager;
49 : use Ding\Bean\Factory\Exception\BeanFactoryException;
50 : use Ding\Bean\BeanConstructorArgumentDefinition;
51 : use Ding\Bean\BeanDefinition;
52 : use Ding\Bean\BeanPropertyDefinition;
53 : use Ding\MessageSource\IMessageSource;
54 :
55 : /**
56 : * Container implementation.
57 : *
58 : * PHP Version 5
59 : *
60 : * @category Ding
61 : * @package Container
62 : * @subpackage Impl
63 : * @author Marcelo Gornstein <marcelog@gmail.com>
64 : * @license http://marcelog.github.com/ Apache License 2.0
65 : * @link http://marcelog.github.com/
66 : */
67 : class ContainerImpl implements IContainer
68 : {
69 : /**
70 : * Signals to handle.
71 : * @var array
72 : */
73 : private $_signals = array(
74 : SIGQUIT, SIGHUP, SIGINT, SIGCHLD, SIGTERM, SIGUSR1, SIGUSR2
75 : );
76 : /**
77 : * Logger.
78 : * @var Logger
79 : */
80 : private $_logger;
81 :
82 : /**
83 : * Cache for isDebugEnabled()
84 : * @var boolean
85 : */
86 : private $_logDebugEnabled;
87 :
88 : /**
89 : * Dispatcher to be cloned for proxy.
90 : * @var DispatcherImpl
91 : */
92 : private $_dispatcherTemplate = null;
93 :
94 : /**
95 : * MessageSource implementation.
96 : * @var IMessageSource
97 : */
98 : private $_messageSource = false;
99 : /**
100 : * Default options.
101 : * @var array
102 : */
103 : private static $_options = array(
104 : 'bdef' => array(),
105 : 'properties' => array(),
106 : 'drivers' => array()
107 : );
108 :
109 : /**
110 : * Registered shutdown methods for beans (destroy-methods).
111 : * @var array
112 : */
113 : private $_shutdowners = array();
114 :
115 : /**
116 : * Beans already instantiated.
117 : * @var object[]
118 : */
119 : private $_beans;
120 :
121 : /**
122 : * Holds our beans cache.
123 : * @var ICache
124 : */
125 : private $_beanCache;
126 :
127 : /**
128 : * Beans already instantiated.
129 : * @var BeanDefinition[]
130 : */
131 : private $_beanDefs;
132 :
133 : /**
134 : * Beans aliases.
135 : * @var string[]
136 : */
137 : private $_beanAliases;
138 :
139 : /**
140 : * Holds our bean definitions cache.
141 : * @var ICache
142 : */
143 : private $_beanDefCache;
144 :
145 : /**
146 : * Container instance.
147 : * @var ContainerImpl
148 : */
149 : private static $_containerInstance = false;
150 :
151 : /**
152 : * The aspect manager.
153 : * @var AspectManager
154 : */
155 : private $_aspectManager = null;
156 :
157 : /**
158 : * The lifecycle manager.
159 : * @var BeanLifecycleManager
160 : */
161 : private $_lifecycleManager = null;
162 :
163 : /**
164 : * Resources multiton.
165 : * @var IResource[]
166 : */
167 : private $_resources = false;
168 :
169 : /**
170 : * The event listeners
171 : * @var string[]
172 : */
173 : private $_eventListeners = false;
174 :
175 : /**
176 : * Bean Definition providers.
177 : * @var IBeanDefinitionProvider[]
178 : */
179 : private $_beanDefinitionProviders = array();
180 :
181 : /**
182 : * The last error message is saved, just to avoid logging repeated messages.
183 : * @var string
184 : */
185 : private $_lastErrorMessage;
186 :
187 : /**
188 : * A ReflectionFactory implementation
189 : * @var IReflectionFactory
190 : */
191 : private $_reflectionFactory;
192 :
193 : /**
194 : * A Proxy factory implementation.
195 : * @var Proxy
196 : */
197 : private $_proxyFactory;
198 :
199 : private $_properties;
200 :
201 : /**
202 : * Prevent serialization.
203 : *
204 : * @return array
205 : */
206 : public function __sleep()
207 : {
208 1 : return array('_aspectManager', '_lifecycleManager');
209 : }
210 :
211 : /**
212 : * (non-PHPdoc)
213 : * @see Ding\Bean.IBeanDefinitionProvider::getBeanDefinitionByClass()
214 : */
215 : public function getBeanDefinitionByClass($class)
216 : {
217 3 : foreach ($this->_beanDefinitionProviders as $provider) {
218 3 : $beanDefinition = $provider->getBeanDefinitionByClass($class);
219 3 : }
220 3 : }
221 : /**
222 : * Returns a bean definition.
223 : *
224 : * @param string $name Bean name.
225 : *
226 : * @return BeanDefinition
227 : * @throws BeanFactoryException
228 : */
229 : public function getBeanDefinition($name)
230 : {
231 264 : $beanName = $name . '.beandef';
232 264 : if (isset($this->_beanAliases[$name])) {
233 1 : $name = $this->_beanAliases[$name];
234 1 : }
235 264 : if (isset($this->_beanDefs[$name])) {
236 30 : return $this->_beanDefs[$name];
237 : }
238 :
239 264 : $beanDefinition = null;
240 264 : if ($this->_beanDefCache !== null) {
241 264 : $beanDefinition = $this->_beanDefCache->fetch($beanName, $result);
242 264 : }
243 264 : if ($beanDefinition) {
244 64 : $this->_beanDefs[$name] = $beanDefinition;
245 64 : return $beanDefinition;
246 : }
247 264 : foreach ($this->_beanDefinitionProviders as $provider) {
248 264 : $beanDefinition = $provider->getBeanDefinition($name);
249 264 : if ($beanDefinition) {
250 264 : $beanDefinition->setClass($this->_searchAndReplaceProperties(
251 264 : $beanDefinition->getClass()
252 264 : ));
253 264 : break;
254 : }
255 264 : }
256 264 : if (!$beanDefinition) {
257 258 : throw new BeanFactoryException('Unknown bean: ' . $name);
258 : }
259 264 : $beanDefinition = $this->_lifecycleManager->afterDefinition($beanDefinition);
260 264 : $this->_beanDefs[$beanName] = $beanDefinition;
261 264 : $this->_beanDefCache->store($beanName, $beanDefinition);
262 264 : foreach ($beanDefinition->getAliases() as $alias) {
263 16 : $this->_beanAliases[$alias] = $name;
264 264 : }
265 264 : return $beanDefinition;
266 : }
267 :
268 : private function _searchAndReplaceProperties($value)
269 : {
270 264 : if (is_string($value)) {
271 264 : foreach ($this->_properties as $k => $v) {
272 24 : if (strpos($value, $k) !== false) {
273 18 : if (is_string($v)) {
274 18 : $value = str_replace($k, $v, $value);
275 18 : } else {
276 12 : $value = $v;
277 : }
278 18 : }
279 264 : }
280 264 : }
281 264 : return $value;
282 : }
283 :
284 : /**
285 : * Takes care of transforming a scalar value for a property or constructor
286 : * argument, into a an actual value (i.e: if its a resource://, loading it
287 : * first).
288 : *
289 : * @param mixed $value The value
290 : *
291 : * @return mixed
292 : */
293 : private function _loadValue($value)
294 : {
295 264 : $value = $this->_searchAndReplaceProperties($value);
296 264 : if (is_string($value) && strpos($value, 'resource://') === 0) {
297 2 : $value = substr($value, 11);
298 2 : return $this->getResource($value);
299 : }
300 264 : return $value;
301 : }
302 :
303 : /**
304 : * This will resolve a property (or constructor arg) definition to a final
305 : * value, being a bean reference, array of other properties (or
306 : * constructor args), etc.
307 : *
308 : * @param BeanPropertyDefinition|BeanConstructorArgumentDefinition $what
309 : *
310 : * @return void
311 : */
312 : private function _getValueFromDefinition($what)
313 : {
314 264 : $value = null;
315 264 : if ($what->isBean()) {
316 264 : $value = $this->getBean($what->getValue());
317 264 : } else if ($what->isArray()) {
318 50 : $value = array();
319 50 : foreach ($what->getValue() as $k => $v) {
320 50 : $value[$k] = $this->_getValueFromDefinition($v);
321 50 : }
322 264 : } else if ($what->isCode()) {
323 24 : $value = eval($what->getValue());
324 24 : } else {
325 264 : $value = $this->_loadValue($what->getValue());
326 : }
327 264 : return $value;
328 : }
329 :
330 : /**
331 : * Resolves all values for constructor arguments definitions in a
332 : * bean definition.
333 : *
334 : * @param BeanDefinition $definition
335 : *
336 : * @return object
337 : */
338 : private function _getConstructorValuesForDefinition($definition)
339 : {
340 264 : $args = array();
341 264 : foreach ($definition->getArguments() as $argument) {
342 264 : $args[] = $this->_getValueFromDefinition($argument);
343 264 : }
344 264 : return $args;
345 : }
346 :
347 : /**
348 : * Instantiates a bean using the constructor.
349 : *
350 : * @param BeanDefinition $definition
351 : *
352 : * @return object
353 : */
354 : private function _instantiateByConstructor(BeanDefinition $definition)
355 : {
356 264 : $args = $this->_getConstructorValuesForDefinition($definition);
357 264 : $class = $definition->getClass();
358 264 : if ($definition->hasProxyClass()) {
359 24 : $class = $definition->getProxyClassName();
360 24 : }
361 264 : $rClass = $this->_reflectionFactory->getClass($class);
362 264 : if (empty($args)) {
363 264 : return $rClass->newInstanceArgs();
364 : } else {
365 264 : return $rClass->newInstanceArgs($args);
366 : }
367 : }
368 :
369 : /**
370 : * Instantiates a bean using a factory class.
371 : *
372 : * @param BeanDefinition $definition
373 : *
374 : * @return object
375 : */
376 : private function _instantiateByFactoryClass(BeanDefinition $definition)
377 : {
378 264 : $args = $this->_getConstructorValuesForDefinition($definition);
379 264 : return forward_static_call_array(
380 264 : array($definition->getClass(), $definition->getFactoryMethod()),
381 : $args
382 264 : );
383 : }
384 :
385 : /**
386 : * Instantiates a bean using a factory bean.
387 : *
388 : * @param BeanDefinition $definition
389 : *
390 : * @return object
391 : */
392 : private function _instantiateByFactoryBean(BeanDefinition $definition)
393 : {
394 65 : $args = $this->_getConstructorValuesForDefinition($definition);
395 65 : $factoryBean = $this->getBean($definition->getFactoryBean());
396 65 : $refObject = new \ReflectionObject($factoryBean);
397 65 : $factoryMethod = $refObject->getMethod($definition->getFactoryMethod());
398 65 : return $factoryMethod->invokeArgs($factoryBean, $args);
399 : }
400 :
401 : /**
402 : * Instantiates a bean.
403 : *
404 : * @param BeanDefinition $definition
405 : *
406 : * @return object
407 : */
408 : private function _instantiate(BeanDefinition $definition)
409 : {
410 264 : if ($definition->isCreatedByConstructor()) {
411 264 : return $this->_instantiateByConstructor($definition);
412 264 : } else if ($definition->isCreatedWithFactoryBean()) {
413 65 : return $this->_instantiateByFactoryBean($definition);
414 : } else {
415 264 : return $this->_instantiateByFactoryClass($definition);
416 : }
417 : }
418 :
419 : /**
420 : * Creates whatever beans this definition depends on.
421 : *
422 : * @return void
423 : */
424 : private function _createBeanDependencies(BeanDefinition $definition)
425 : {
426 264 : foreach ($definition->getDependsOn() as $depBean) {
427 6 : $this->getBean(trim($depBean));
428 264 : }
429 264 : }
430 :
431 : /**
432 : * Will inject into the given dispatcher the necessary information to
433 : * aspects will be run correctly.
434 : *
435 : * @throws BeanFactoryException
436 : * @return void
437 : */
438 : private function _applyAspect(
439 : $targetClass, AspectDefinition $aspectDefinition, IDispatcher $dispatcher
440 : ) {
441 25 : $rClass = $this->_reflectionFactory->getClass($targetClass);
442 25 : $aspect = $this->getBean($aspectDefinition->getBeanName());
443 25 : foreach ($aspectDefinition->getPointcuts() as $pointcutName) {
444 25 : $pointcut = $this->_aspectManager->getPointcut($pointcutName);
445 25 : if ($pointcut === false) {
446 1 : throw new BeanFactoryException('Could not find pointcut: ' . $pointcutName);
447 : }
448 24 : $expression = $pointcut->getExpression();
449 24 : foreach ($rClass->getMethods() as $method) {
450 24 : $methodName = $method->getName();
451 24 : if (preg_match('/' . $expression . '/', $methodName) === 0) {
452 8 : continue;
453 : }
454 : if (
455 24 : $aspectDefinition->getType() == AspectDefinition::ASPECT_METHOD
456 24 : ) {
457 21 : $dispatcher->addMethodInterceptor($methodName, $aspect, $pointcut->getMethod());
458 21 : } else {
459 5 : $dispatcher->addExceptionInterceptor($methodName, $aspect, $pointcut->getMethod());
460 : }
461 24 : }
462 24 : }
463 24 : }
464 :
465 : /**
466 : * Applies all aspects specifically defined for this bean definition.
467 : *
468 : * @param BeanDefinition $definition
469 : * @param IDispatcher $dispatcher
470 : *
471 : * @return void
472 : */
473 : private function _applySpecificAspects(BeanDefinition $definition, IDispatcher $dispatcher)
474 : {
475 264 : if ($definition->hasAspects()) {
476 17 : foreach ($definition->getAspects() as $aspect) {
477 17 : $this->_applyAspect($definition->getClass(), $aspect, $dispatcher);
478 17 : }
479 17 : }
480 264 : }
481 :
482 : /**
483 : * Looks for any global aspects that may apply to this bean and applies them.
484 : *
485 : * @param BeanDefinition $definition
486 : * @param IDispatcher $dispatcher
487 : *
488 : * @return void
489 : */
490 : private function _applyGlobalAspects(BeanDefinition $definition, IDispatcher $dispatcher)
491 : {
492 264 : $class = $definition->getClass();
493 264 : $rClass = $this->_reflectionFactory->getClass($class);
494 264 : foreach ($this->_aspectManager->getAspects() as $aspect) {
495 27 : $expression = $aspect->getExpression();
496 27 : if (preg_match('/' . $expression . '/', $class) === 0) {
497 27 : $parentClass = $rClass->getParentClass();
498 27 : while($parentClass !== false) {
499 1 : if (preg_match('/' . $expression . '/', $parentClass->getName()) > 0) {
500 1 : $this->_applyAspect($parentClass->getName(), $aspect, $dispatcher);
501 1 : }
502 1 : $parentClass = $parentClass->getParentClass();
503 1 : }
504 27 : } else {
505 7 : $this->_applyAspect($class, $aspect, $dispatcher);
506 : }
507 264 : }
508 264 : }
509 :
510 : /**
511 : * Applies specific bean aspects and global defined aspects.
512 : *
513 : * @param BeanDefinition $definition
514 : *
515 : * @return void
516 : */
517 : private function _applyAspects(BeanDefinition $definition)
518 : {
519 264 : $class = $definition->getClass();
520 264 : if (empty($class)) {
521 1 : return;
522 : }
523 264 : $dispatcher = clone $this->_dispatcherTemplate;
524 264 : $this->_applySpecificAspects($definition, $dispatcher);
525 264 : $this->_applyGlobalAspects($definition, $dispatcher);
526 264 : if ($dispatcher->hasMethodsIntercepted()) {
527 24 : $definition->setProxyClassName(
528 24 : $this->_proxyFactory->create($class, $dispatcher)
529 24 : );
530 24 : }
531 264 : }
532 : /**
533 : * This will create a new bean, injecting all properties and applying all
534 : * aspects.
535 : *
536 : * @throws BeanFactoryException
537 : * @return object
538 : */
539 : private function _createBean(BeanDefinition $definition)
540 : {
541 264 : $this->_lifecycleManager->beforeCreate($definition);
542 264 : $this->_createBeanDependencies($definition);
543 264 : $this->_applyAspects($definition);
544 264 : $bean = $this->_instantiate($definition);
545 264 : $this->_assemble($bean, $definition);
546 264 : $this->_setupInitAndShutdown($bean, $definition);
547 264 : $this->_lifecycleManager->afterCreate($bean, $definition);
548 264 : return $bean;
549 : }
550 :
551 : /**
552 : * Calls init method and register shutdown method.
553 : *
554 : * @param object $bean
555 : * @param BeanDefinition $definition
556 : *
557 : * @return void
558 : */
559 : private function _setupInitAndShutdown($bean, BeanDefinition $definition)
560 : {
561 264 : if ($definition->hasInitMethod()) {
562 23 : $initMethod = $definition->getInitMethod();
563 23 : $bean->$initMethod();
564 23 : }
565 264 : if ($definition->hasDestroyMethod()) {
566 22 : $destroyMethod = $definition->getDestroyMethod();
567 22 : $this->registerShutdownMethod($bean, $destroyMethod);
568 22 : }
569 264 : }
570 : /**
571 : * Assembles a bean (setter injection)
572 : *
573 : * @param mixed $bean
574 : * @param BeanDefinition $beanDefinition
575 : *
576 : * @return void
577 : */
578 : private function _assemble($bean, BeanDefinition $beanDefinition)
579 : {
580 264 : $this->_lifecycleManager->beforeAssemble($bean, $beanDefinition);
581 264 : foreach ($beanDefinition->getProperties() as $property) {
582 264 : $propertyName = $property->getName();
583 264 : $methodName = 'set' . ucfirst($propertyName);
584 264 : $rClass = $this->_reflectionFactory->getClass($beanDefinition->getClass());
585 264 : if ($rClass->hasMethod($methodName)) {
586 264 : $bean->$methodName($this->_getValueFromDefinition($property));
587 264 : }
588 264 : }
589 264 : $this->fillAware($beanDefinition, $bean);
590 264 : $this->_lifecycleManager->afterAssemble($bean, $beanDefinition);
591 264 : }
592 : /**
593 : * Returns a bean.
594 : *
595 : * @param string $name Bean name.
596 : *
597 : * @throws BeanFactoryException
598 : * @return object
599 : */
600 : public function getBean($name)
601 : {
602 264 : $ret = false;
603 264 : $beanDefinition = $this->getBeanDefinition($name);
604 264 : $beanName = $name . '.bean';
605 264 : if ($beanDefinition->isAbstract()) {
606 1 : throw new BeanFactoryException(
607 1 : "Cant instantiate abstract bean: $name"
608 1 : );
609 : }
610 264 : if ($beanDefinition->isPrototype()) {
611 38 : $ret = $this->_createBean($beanDefinition);
612 264 : } else if ($beanDefinition->isSingleton()) {
613 264 : if (isset($this->_beans[$beanName])) {
614 165 : $ret = $this->_beans[$beanName];
615 165 : } else {
616 264 : $ret = $this->_beanCache->fetch($beanName, $result);
617 264 : if (!$ret) {
618 264 : $ret = $this->_createBean($beanDefinition);
619 264 : }
620 264 : $this->_beans[$beanName] = $ret;
621 : }
622 264 : }
623 264 : return $ret;
624 : }
625 :
626 : /**
627 : * This will return a container
628 : *
629 : * @param array $properties Container properties.
630 : *
631 : * @return ContainerImpl
632 : */
633 : public static function getInstance(array $properties = array())
634 : {
635 264 : if (self::$_containerInstance === false) {
636 : // Init cache subsystems.
637 264 : if (isset($properties['ding']['cache'])) {
638 151 : CacheLocator::configure($properties['ding']['cache']);
639 151 : }
640 264 : \Ding\Autoloader\Autoloader::setCache(CacheLocator::getAutoloaderCacheInstance());
641 264 : if (isset($properties['ding']['log4php.properties'])) {
642 264 : \Logger::configure($properties['ding']['log4php.properties']);
643 264 : }
644 264 : self::$_containerInstance = new ContainerImpl($properties['ding']['factory']);
645 260 : }
646 260 : return self::$_containerInstance;
647 : }
648 :
649 : /**
650 : * Register a shutdown (destroy-method) method for a bean.
651 : *
652 : * @param object $bean Bean to call.
653 : * @param string $method Method to call.
654 : *
655 : * @see Ding\Container.IContainer::registerShutdownMethod()
656 : *
657 : * @return void
658 : */
659 : public function registerShutdownMethod($bean, $method)
660 : {
661 22 : $this->_shutdowners[] = array($bean, $method);
662 22 : }
663 :
664 : /**
665 : * Destructor, will call all beans destroy-methods.
666 : *
667 : * @return void
668 : */
669 : public function __destruct()
670 : {
671 16 : foreach ($this->_shutdowners as $shutdownCall) {
672 16 : $bean = $shutdownCall[0];
673 16 : $method = $shutdownCall[1];
674 16 : $bean->$method();
675 16 : }
676 16 : }
677 :
678 : /**
679 : *
680 : * Enter description here ...
681 : * @param unknown_type $messageSource
682 : */
683 : public function setMessageSource(IMessageSource $messageSource)
684 : {
685 2 : $this->_messageSource = $messageSource;
686 2 : }
687 :
688 : /**
689 : * (non-PHPdoc)
690 : * @see Ding\MessageSource.IMessageSource::getMessage()
691 : */
692 : public function getMessage($bundle, $message, array $arguments, $locale)
693 : {
694 : return
695 2 : $this->_messageSource !== false
696 2 : ? $this->_messageSource->getMessage($bundle, $message, $arguments, $locale)
697 2 : : NULL;
698 : }
699 :
700 : /**
701 : * (non-PHPdoc)
702 : * @see Ding\Resource.IResourceLoader::getResource()
703 : */
704 : public function getResource($location, $context = false)
705 : {
706 : // Missing scheme?
707 7 : $scheme = strpos($location, '://');
708 7 : if ($scheme === false) {
709 1 : $location = FilesystemResource::SCHEME . $location;
710 1 : }
711 : // Already served?
712 7 : if (isset($this->_resources[$location])) {
713 1 : return $this->_resources[$location];
714 : }
715 : // See what kind of resource to return.
716 7 : if (strpos($location, FilesystemResource::SCHEME) === 0) {
717 3 : $resource = new FilesystemResource($location, $context);
718 7 : } else if (strpos($location, IncludePathResource::SCHEME) === 0) {
719 3 : $resource = new IncludePathResource($location, $context);
720 3 : } else {
721 1 : $resource = new URLResource($location, $context);
722 : }
723 7 : $this->_resources[$location] = $resource;
724 7 : return $resource;
725 : }
726 :
727 : /**
728 : * (non-PHPdoc)
729 : * @see Ding\Container.IContainer::eventDispatch()
730 : */
731 : public function eventDispatch($eventName, $data = null)
732 : {
733 14 : $eventName = 'on' . ucfirst($eventName);
734 14 : if (isset($this->_eventListeners[$eventName])) {
735 5 : foreach ($this->_eventListeners[$eventName] as $beanName) {
736 5 : $bean = $this->getBean($beanName);
737 5 : $bean->$eventName($data);
738 5 : }
739 5 : }
740 14 : }
741 :
742 : /**
743 : * (non-PHPdoc)
744 : * @see Ding\Container.IContainer::eventListen()
745 : */
746 : public function eventListen($eventName, $beanName)
747 : {
748 7 : if (!isset($this->_eventListeners[$eventName])) {
749 7 : $this->_eventListeners[$eventName] = array();
750 7 : }
751 7 : $eventName = 'on' . ucfirst($eventName);
752 7 : $this->_eventListeners[$eventName][] = $beanName;
753 7 : }
754 :
755 : /**
756 : * (non-PHPdoc)
757 : * @see Ding\Container.IContainer::registerBeanDefinitionProvider()
758 : */
759 : public function registerBeanDefinitionProvider(IBeanDefinitionProvider $provider)
760 : {
761 264 : $this->_beanDefinitionProviders[] = $provider;
762 264 : }
763 :
764 : /**
765 : * If we dont have a ReflectionFactory yet (i.e: didnt make the call to
766 : * getBean() yet), replace it with this one.
767 : *
768 : * @param string $class The name of a class.
769 : *
770 : * @return ReflectionClass
771 : */
772 : protected function getClass($class)
773 : {
774 264 : return new \ReflectionClass($class);
775 : }
776 :
777 : /**
778 : * Will look for "aware" kind of interfaces and inject whatever necessary.
779 : *
780 : * @param BeanDefinition $def The Bean Definition
781 : * @param object $bean The bean
782 : *
783 : * @return void
784 : */
785 : public function fillAware(BeanDefinition $def, $bean)
786 : {
787 264 : $class = get_class($bean);
788 264 : $rClass = $this->_reflectionFactory->getClass($class);
789 264 : if ($rClass->implementsInterface('Ding\Reflection\IReflectionFactoryAware')) {
790 264 : $bean->setReflectionFactory($this->_reflectionFactory);
791 264 : }
792 264 : if ($rClass->implementsInterface('Ding\Bean\IBeanNameAware')) {
793 1 : $bean->setBeanName($def->getName());
794 1 : }
795 264 : if ($rClass->implementsInterface('Ding\Logger\ILoggerAware')) {
796 190 : $bean->setLogger(\Logger::getLogger($class));
797 190 : }
798 264 : if ($rClass->implementsInterface('Ding\Container\IContainerAware')) {
799 264 : $bean->setContainer($this);
800 264 : }
801 264 : if ($rClass->implementsInterface('Ding\Resource\IResourceLoaderAware')) {
802 260 : $bean->setResourceLoader($this);
803 260 : }
804 264 : if ($rClass->implementsInterface('Ding\Aspect\IAspectManagerAware')) {
805 264 : $bean->setAspectManager($this->_aspectManager);
806 264 : }
807 264 : if ($rClass->implementsInterface('Ding\Bean\IBeanDefinitionProvider')) {
808 264 : $this->registerBeanDefinitionProvider($bean);
809 264 : }
810 264 : if ($rClass->implementsInterface('Ding\Bean\Lifecycle\IAfterConfigListener')) {
811 264 : $this->_lifecycleManager->addAfterConfigListener($bean);
812 264 : }
813 264 : if ($rClass->implementsInterface('Ding\Bean\Lifecycle\IAfterDefinitionListener')) {
814 260 : $this->_lifecycleManager->addAfterDefinitionListener($bean);
815 260 : }
816 264 : if ($rClass->implementsInterface('Ding\Bean\Lifecycle\IBeforeCreateListener')) {
817 1 : $this->_lifecycleManager->addBeforeCreateListener($bean);
818 1 : }
819 264 : if ($rClass->implementsInterface('Ding\Bean\Lifecycle\IAfterCreateListener')) {
820 260 : $this->_lifecycleManager->addAfterCreateListener($bean);
821 260 : }
822 264 : if ($rClass->implementsInterface('Ding\Bean\Lifecycle\IBeforeAssembleListener')) {
823 1 : $this->_lifecycleManager->addBeforeAssembleListener($bean);
824 1 : }
825 264 : if ($rClass->implementsInterface('Ding\Bean\Lifecycle\IAfterAssembleListener')) {
826 1 : $this->_lifecycleManager->addAfterAssembleListener($bean);
827 1 : }
828 264 : if ($rClass->implementsInterface('Ding\Aspect\IAspectProvider')) {
829 189 : $this->_aspectManager->registerAspectProvider($bean);
830 185 : }
831 264 : if ($rClass->implementsInterface('Ding\Aspect\IPointcutProvider')) {
832 185 : $this->_aspectManager->registerPointcutProvider($bean);
833 185 : }
834 264 : }
835 :
836 : /**
837 : * Called when a signal is caught.
838 : *
839 : * @param integer $signo
840 : *
841 : * @return void
842 : */
843 : public function signalHandler($signo)
844 : {
845 2 : $msg = "Caught Signal: $signo";
846 2 : $this->_logger->warn($msg);
847 2 : $this->eventDispatch('dingSignal', $signo);
848 2 : }
849 :
850 : /**
851 : * Called by php after set_error_handler()
852 : *
853 : * @param integer $type
854 : * @param string $message
855 : * @param string $file
856 : * @param integer $line
857 : *
858 : * @return true
859 : */
860 : public function errorHandler($type, $message, $file, $line)
861 : {
862 11 : $msg = "$message in $file:$line";
863 11 : if ($msg == $this->_lastErrorMessage) {
864 1 : return;
865 : }
866 11 : $this->_lastErrorMessage = $msg;
867 11 : $this->_logger->error($msg);
868 11 : $this->eventDispatch(
869 11 : 'dingError', new ErrorInfo($type, $message, $file, $line)
870 11 : );
871 11 : return true;
872 : }
873 :
874 : // @codeCoverageIgnoreStart
875 : /**
876 : * Called by the vm after register_shutdown_function()
877 : *
878 : * @return void
879 : */
880 : public function shutdownHandler()
881 : {
882 : $msg = "Shutting down";
883 : $this->eventDispatch('dingShutdown');
884 : }
885 : // @codeCoverageIgnoreEnd
886 :
887 : /**
888 : * (non-PHPdoc)
889 : * @see Ding\Container.IContainer::registerProperties()
890 : */
891 : public function registerProperties(array $properties)
892 : {
893 264 : foreach ($properties as $key => $value) {
894 24 : if (strncmp($key, 'php.', 4) === 0) {
895 2 : ini_set(substr($key, 4), $value);
896 2 : }
897 24 : $this->_properties['${' . $key . '}'] = $value;
898 264 : }
899 264 : }
900 :
901 : /**
902 : * Constructor.
903 : *
904 : * @param array $options options.
905 : *
906 : * @return void
907 : */
908 : protected function __construct(array $options)
909 : {
910 : // Setup logger.
911 264 : $this->_logger = \Logger::getLogger(get_class($this));
912 264 : $this->_logDebugEnabled = $this->_logger->isDebugEnabled();
913 264 : $soullessArray = array();
914 264 : $this->_beanAliases = $soullessArray;
915 264 : $this->_beanDefs = $soullessArray;
916 264 : $this->_beans = $soullessArray;
917 264 : $this->_shutdowners = $soullessArray;
918 264 : $this->_resources = $soullessArray;
919 264 : $this->_eventListeners = $soullessArray;
920 264 : $this->_properties = $soullessArray;
921 :
922 : // Merge options with our defaults.
923 264 : self::$_options = array_replace_recursive(self::$_options, $options);
924 264 : $this->registerProperties(self::$_options['properties']);
925 264 : $sapi = php_sapi_name();
926 264 : if ($sapi == 'cgi' || $sapi == 'cli') {
927 264 : $handler = array($this, 'signalHandler');
928 264 : foreach ($this->_signals as $signal) {
929 264 : pcntl_signal($signal, $handler);
930 264 : }
931 264 : pcntl_sigprocmask(SIG_UNBLOCK, $this->_signals);
932 264 : }
933 264 : set_error_handler(array($this, 'errorHandler'));
934 264 : register_shutdown_function(array($this, 'shutdownHandler'));
935 :
936 : // We need a lifecycle manager.
937 264 : $this->_lifecycleManager = new BeanLifecycleManager;
938 264 : $this->_dispatcherTemplate = new DispatcherImpl();
939 264 : $this->_aspectManager = new AspectManager();
940 264 : $this->_beanDefCache = DummyCacheImpl::getInstance();
941 264 : $this->_beanCache = DummyCacheImpl::getInstance();
942 264 : $this->registerBeanDefinitionProvider(new Core(self::$_options));
943 264 : $this->_reflectionFactory = $this;
944 264 : $this->_reflectionFactory = $this->getBean('dingReflectionFactory');
945 264 : $this->_proxyFactory = $this->getBean('dingProxyFactory');
946 264 : $this->_beanDefCache = $this->getBean('dingDefinitionsCache');
947 264 : $this->_beanCache = $this->getBean('dingBeanCache');
948 264 : $this->_lifecycleManager = $this->getBean('dingLifecycleManager');
949 264 : $this->_aspectManager = $this->getBean('dingAspectManager');
950 264 : $this->_dispatcherTemplate = $this->getBean('dingAspectCallDispatcher');
951 :
952 : // Set drivers
953 264 : if (isset(self::$_options['bdef']['xml'])) {
954 162 : $xmlDriver = $this->getBean('dingXmlBeanDefinitionProvider');
955 160 : }
956 262 : if (isset(self::$_options['bdef']['yaml'])) {
957 35 : $yamlDriver = $this->getBean('dingYamlBeanDefinitionProvider');
958 33 : }
959 260 : $this->getBean('dingPropertiesDriver');
960 260 : $this->getBean('dingMessageSourceDriver');
961 260 : $this->getBean('dingMethodInjectionDriver');
962 :
963 : // All set, continue.
964 260 : if (isset(self::$_options['bdef']['annotation'])) {
965 105 : $anDriver = $this->getBean('dingAnnotationBeanDefinitionProvider');
966 105 : $this->getBean('dingAnnotationAspectDriver');
967 105 : $this->getBean('dingAnnotationResourceDriver');
968 105 : $this->getBean('dingAnnotationInitDestroyMethodDriver');
969 105 : $this->getBean('dingAnnotationRequiredDriver');
970 105 : $this->getBean('dingMvcAnnotationDriver');
971 105 : }
972 260 : $this->_lifecycleManager->afterConfig();
973 260 : }
974 : }
|